#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void func() {
    int arr[5] = {1,2,3,4,5};
    int *p = (int*)(&arr + 1); // 数组的地址+1：移动整个数组的大小
    int *q = (int*)(arr + 1); // 数组首元素地址+1：移动数组首元素的大小
    printf("*(arr + 1) = %d\n", *(arr + 1));
    printf("*(p - 1) = %d\n", *(p - 1));
    printf("*(q - 1) = %d\n", *(q - 1));

    printf("&arr = %p\n", &arr); // arr 与 &arr 值相同但含义不同
    printf("arr = %p\n", arr); // arr == &arr[0]
    printf("arr + 1 = %p\n", arr + 1); // 数组名当成首元素的指针使用
    // arr是int (*)类型的指针，因此arr + 1会偏移int 个字节
    printf("&arr + 1 = %p\n", &arr + 1); // &arr获取了这个数组的地址，并返回一个指向该数组的指针
    // &arr是int (*)[5]类型的指针，因此&arr + 1会偏移int [5]个字节
}

void func2(){
    printf("sizeof(long) = %d\n", sizeof(long)); // 4
    char *str = "abcdefgh", *p;
    long *q;
    // q = str; // incompatible pointer type
    q = (long*)str; // 将字符指针str存放的地址赋值给q，由于指针类型不匹配需要进行强转
    printf("*q = %ld\n", *q);
    q++; // q是long *类型，q++偏移4个字节
    p = (char*)q; 
    printf("%s\n", p);
}

void func3(){
    int arr[4][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}};
    int (*p)[3] = arr, *q = arr[0];

    // *q = arr[0]：arr[0]是二维数组arr的第一个元素，相当于一个一维数组的数组名
    // arr[0]可以视为该一维数组的首元素地址的指针，arr[0] == &arr[0][0] 即int *类型
    
    printf("*(arr + 1)[2] = %d\n", *(arr + 1)[2]);
    if (*(arr + 1)[2] == *((arr + 1)[2]) &&
        *((arr + 1)[2]) == *(*((arr + 1) + 2))){
        printf("A\n");
    }
    // *(*(arr + 1)[2]); // 等价于 ***(arr + 1 + 2)
    // 错误：二维数组最多解引用两次，[]也相当于一次*

    if (arr + 1 == *(arr + 1)){
        printf("B\n");
    }

    printf("*((p + 1)[2]) = %d\n", *((p + 1)[2]));
    if (arr[1][2] == *((p + 1)[2])){
                printf("C\n");
    }

    printf("(*p + 1) + 2 = %d\n", (*p + 1) + 2);
    if (arr[1][2] == (*p + 1) + 2){
        printf("C\n");
    }
}

int main() {
    func();
    func2();
    func3();
    return 0;
}